package fr.gdi.android.news;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.BufferType;

import com.android.extras.TouchInterceptor;

import fr.gdi.android.news.utils.Constants;
import fr.gdi.android.news.utils.Constants.ExtraTags;
import fr.gdi.android.news.utils.FeedUtils;
import fr.gdi.android.news.utils.PreferenceUtils;
import fr.gdi.android.news.utils.Utils;

public class EditFeedActivity extends ListActivity implements OnClickListener
{
    
    public final static String TAG_SKIP_UPDATE = "SkipUpdate";
    private final static int requestAddFeed = 1;
    private final static int requestSelectFile = 2;
    
    private final static SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMdd");
    
    private static final int EXPORT_FEEDS_DLG = 1;
    private static final int IMPORTER_DLG = 2;
    private static final int ADD_FEED_DLG = 4;
    
    private List<FeedDescription> feeds;
    private FeedAdapter adapter;
    private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    private boolean skipUpdate = false;
    private ListView feedList;
    
    private Map<String, Integer> colors = new HashMap<String, Integer>();
    
    private static class LocalActivityInfo
    {
        String label;
        String cls;
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_widget_configuration);
        findViewById(R.id.save).setOnClickListener(this);
        Button btn = (Button) findViewById(R.id.cancel);
        btn.setText(android.R.string.cancel);
        btn.setOnClickListener(this);
        
        btn = (Button) findViewById(R.id.export_feeds);
        btn.setOnClickListener(this);
        
        btn = (Button) findViewById(R.id.import_feeds);
        btn.setOnClickListener(this);
        
        feedList = getListView();
        registerForContextMenu(feedList);
        
        ((TouchInterceptor) feedList).setDropListener(mDropListener);
        ((TouchInterceptor) feedList).setRemoveListener(mRemoveListener);
        ((TouchInterceptor) feedList).setRemoveMode(TouchInterceptor.FLING);
        feedList.setCacheColorHint(0);
        
        init();
    }
    
    private void init()
    {
        feeds = FeedUtils.getFeedDescriptions(this, null);
        adapter = new FeedAdapter(this, feeds);
        feeds.add(new FeedDescription(this.getString(R.string.add_feed), null));
        feedList.setAdapter(adapter);
        
    }
    
    @Override
    public void onClick(View v)
    {
        switch (v.getId())
        {
            case R.id.cancel:
            {
                finish();
                break;
            }
            case R.id.save:
            {
                savePreferences();
                Intent resultValue = new Intent();
                resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                setResult(RESULT_OK, resultValue);
                if (!skipUpdate)
                {
                    // Uri uri =
                    // URI.CONTENT_URI_FEEDS.buildUpon().appendEncodedPath(Integer.toString(appWidgetId)).build();
                    UpdateService.update(this, appWidgetId);
                }
                finish();
                break;
            }
            case R.id.export_feeds:
                showDialog(EXPORT_FEEDS_DLG);
                break;
            case R.id.import_feeds:
                
                List<LocalActivityInfo> importers = getImporters();
                if ( importers.size() > 1 ) 
                {
                    showDialog(IMPORTER_DLG);
                }
                else
                {
                    Intent intent = new Intent(this, FileChooserActivity.class);
                    startActivityForResult(intent, requestSelectFile);
                }
                break;
        }
    }
    
    private List<LocalActivityInfo> getActivitiesForIntent(String action) 
    {
        final PackageManager packageManager = this.getPackageManager();
        final Intent sampleIntent = new Intent(action);
        
        List<ResolveInfo> list = packageManager.queryIntentActivities(sampleIntent, PackageManager.MATCH_DEFAULT_ONLY);
        List<LocalActivityInfo> infos = new ArrayList<EditFeedActivity.LocalActivityInfo>();
        
        if ( list.size() > 0 )
        {
            for (int u = 0; u < list.size(); u++)
            {
                ResolveInfo info = list.get(u);
                String label = info.loadLabel(packageManager).toString();
                ActivityInfo activityInfo = info.activityInfo;
                LocalActivityInfo i = new LocalActivityInfo();
                i.label = label;
                i.cls = activityInfo.packageName + "/" + activityInfo.name;
                infos.add(i);
            }
        }
        return infos;
    }
    
    private List<LocalActivityInfo> getImporters()
    {
        String action = Constants.Actions.IMPORT;
        return getActivitiesForIntent(action);
    }
    
    private List<LocalActivityInfo> getFeedDefinitionActivities()
    {
        String action = Constants.Actions.ADD_FEED;
        return getActivitiesForIntent(action);
    }
    
    private Dialog createActivitySwitchDialog(int dialogTitleId, final String action, final int actionCode, List<LocalActivityInfo> activityInfos)
    {
        final String[] entries = new String[activityInfos.size()];
        final String[] values = new String[activityInfos.size()];
        
        for (int u = 0, l = activityInfos.size(); u < l; u++)
        {
            LocalActivityInfo a = activityInfos.get(u);
            entries[u] = a.label;
            values[u] = a.cls;
        }
        
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(dialogTitleId);
        builder.setItems(entries, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int item) 
            {
                String val = values[item];
                String[] parts = val.split("\\/");
                ComponentName cn = new ComponentName(parts[0], parts[1]);
                Intent intent = new Intent(action).setComponent(cn);
                startActivityForResult(intent, actionCode);
            }
        });
        AlertDialog dlg = builder.create();
        return dlg;
    }
    
    @Override
    protected Dialog onCreateDialog(int id)
    {
        switch (id)
        {
            case IMPORTER_DLG:
                return createActivitySwitchDialog(
                        R.string.import_from, 
                        Constants.Actions.IMPORT, 
                        requestSelectFile, 
                        getImporters());
            case ADD_FEED_DLG:
                return createActivitySwitchDialog(
                        R.string.add_feed, 
                        Constants.Actions.ADD_FEED, 
                        requestAddFeed, 
                        getFeedDefinitionActivities());
            case EXPORT_FEEDS_DLG:
                final Activity activity = this;
                LayoutInflater inflater = getLayoutInflater();
                final View view = inflater.inflate(R.layout.feed_file_name_dialog, null);
                final TextView tv = (TextView) view.findViewById(R.id.feed_filename);
                
                tv.setText("feeds_" + SDF.format(new Date()) + ".opml", BufferType.EDITABLE);
                
                AlertDialog alertDialog = new AlertDialog.Builder(this).setView(view).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which)
                    {
                        dialog.dismiss();
                    }
                }).create();
                alertDialog.setTitle(getString(R.string.export_feeds));
                alertDialog.setCancelable(true);
                alertDialog.setButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which)
                    {
                        try
                        {
                            String filename = tv.getText().toString();
                            FeedUtils.exportFeeds(activity, filename);
                            Utils.showSuccess(activity, "Feeds succesfully exported to sdcard: " + filename);
                        }
                        catch (Exception e)
                        {
                            String msg = "Couldnot export feeds.";
                            Log.e(EditFeedActivity.class.getName(), msg, e);
                            Utils.showError(activity, msg);
                        }
                        finally
                        {
                            dialog.dismiss();
                        }
                    }
                });
                return alertDialog;
            default:
                return null;
        }
    }
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
    {
        if (v == feedList)
        {
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
            
            if (info.position != feeds.size() - 1)
            {
                menu.setHeaderTitle(feeds.get(info.position).name);
                menu.add(Menu.NONE, 0, 0, R.string.edit_feed);
                menu.add(Menu.NONE, 1, 1, R.string.delete_feed);
            }
        }
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem item)
    {
        final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        final int menuItemIndex = item.getItemId();
        final int position = info.position;
        switch (menuItemIndex)
        {
            case 0:
            {
                editFeed(position);
                break;
            }
            case 1:
            {
                String name = feeds.get(position).name;
                feeds.remove(position);
                adapter.notifyDataSetChanged();
                int[] wdigetIds = Utils.getAllWidgetIds(this);
                for (int i : wdigetIds)
                {
                    FeedUtils.removeFeed(this, i, name);
                }
                break;
            }
        }
        return true;
    }
    
    @Override
    public void onListItemClick(ListView l, View view, int position, long id)
    {
        if (position == feeds.size() - 1)
        {
            editFeed(-1);
        }
        else 
        {
            editFeed(position);
        }
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, final Intent data)
    {
        if (requestCode == requestSelectFile)
        {
            if (resultCode == RESULT_OK)
            {
                String path = data.getStringExtra(Constants.FILENAME_KEY);
                
                try
                {
                    final File file = new File(path);
                    FeedUtils.importFeeds(this, file, new Runnable() {
                        @Override
                        public void run()
                        {
                            init();
                            if ( data.getBooleanExtra("DROP_FILE", false) ) 
                            {
                                if ( file.exists() ) file.delete();
                            }
                        }
                    });
                }
                catch (Exception e)
                {
                    Log.e(this.getClass().getName(), "Unable to import feeds", e);
                    Utils.showError(this, "Could not import feeds");
                }
            }
        }
        else if (requestCode == requestAddFeed)
        {
            if (resultCode == RESULT_OK)
            {
                int position = data.getIntExtra(ExtraTags.TAG_POSITION, -1);
                String name = data.getStringExtra(ExtraTags.TAG_NAME);
                String url = data.getStringExtra(ExtraTags.TAG_URL);
                String pkg = data.getStringExtra(ExtraTags.TAG_PKG);
                Integer color = data.getIntExtra(ExtraTags.TAG_COLOR, -1);
                
                boolean isEdit = data.getBooleanExtra(ExtraTags.TAG_EDIT, false);
                
                String authActivity = data.getStringExtra(ExtraTags.TAG_AUTH); 
                
                if (!isEdit)
                {
                    FeedDescription desc = new FeedDescription(name, url);
                    if (position == -1)
                    {
                        feeds.add(feeds.size() - 1, desc);
                    }
                    else
                    {
                        feeds.add(desc);
                    }
                    
                    if ( !TextUtils.isEmpty(authActivity) ) 
                    {
                        String pref = FeedUtils.getAuthPrefKey(url);
                        PreferenceUtils.setStringPreference(this, pref, authActivity);
                    }
                    
                    if ( !TextUtils.isEmpty(pkg) ) 
                    {
                        String pref = FeedUtils.getPackagePrefKey(pkg);
                        PreferenceUtils.addStringPreference(this, pref, url);
                    }
                }
                else
                {
                    if (position != -1 && position != feeds.size() - 1) // ignore last item
                    {
                        FeedDescription f = feeds.get(position);
                        f.url = url;
                        // TODO allow updating name as well
                        // feeds.get(position).name = name;
                        // update widget settings
                    }
                }
                
                setColor(name, color);
                adapter.notifyDataSetChanged();
            }
        }
        else
        {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
    
    private void setColor(String name, Integer color)
    {
        colors.put(name, color);
    }

    private TouchInterceptor.DropListener mDropListener = new TouchInterceptor.DropListener() {
        public void drop(int from, int to)
        {
            final int last = adapter.getCount() - 1;
            if (from >= last)
            {
                from = last - 1;
            }
            if (to >= last)
            {
                to = last - 1;
            }
            
            try
            {
                FeedDescription curValue = feeds.get(from);
                feeds.set(from, feeds.get(to));
                feeds.set(to, curValue);
                adapter.notifyDataSetChanged();
                getListView().invalidateViews();
            }
            catch ( Exception e ) 
            {
                Log.e(Constants.PACKAGE, "EditFeedActivity.DropListener.drop: Error while editing feed. from=" + from + "to=" + to);
            }
        }
    };
    
    private TouchInterceptor.RemoveListener mRemoveListener = new TouchInterceptor.RemoveListener() {
        public void remove(int which)
        {
            if (which < adapter.getCount() - 1)
            {
                View v = feedList.getChildAt(which - feedList.getFirstVisiblePosition());
                v.setVisibility(View.GONE);
                feedList.invalidateViews();
                feeds.remove(which);
                adapter.notifyDataSetChanged();
                v.setVisibility(View.VISIBLE);
                feedList.invalidateViews();
            }
        }
    };
    
    private void editFeed(final int position)
    {
        //TODO: custom feed provider
        Intent intent = new Intent(this, AddFeedActivity.class);
        intent.setAction(Intent.ACTION_EDIT);
        intent.putExtra(ExtraTags.TAG_POSITION, position);
        intent.putExtra(ExtraTags.TAG_FEEDS, FeedUtils.toCsvString(feeds));
        if (position != -1)
        {
            FeedDescription f = feeds.get(position);
            intent.putExtra(ExtraTags.TAG_NAME, f.name);
            intent.putExtra(ExtraTags.TAG_URL, f.url);
            startActivityForResult(intent, requestAddFeed);
        }
        else
        {
            List<LocalActivityInfo> activities = getFeedDefinitionActivities();
            if ( activities.size() > 1 ) 
            {
                showDialog(ADD_FEED_DLG);
            }
            else
            {
                startActivityForResult(intent, requestAddFeed);
            }
        }
    }
    
    @Override
    protected void onPause()
    {
        this.savePreferences();
        super.onPause();
    }
    
    private void savePreferences()
    {
        String result = FeedUtils.toCsvString(feeds);
        FeedUtils.setFeeds(this, null, result.toString());
        FeedUtils.setFeedColors(this, colors);
    }
}
